#include "stdafx.h"
#include "CdnProfiler.h"
#include "CdnProfTimer.h"
#include "CdnProfilerFn.h"
#include <stdio.h>
#include <assert.h>


namespace prof
{
	//-----------------------------------------------------
	/**
	* static member initialization
	*/
	bool CdnProfiler::m_initialized = false;
	bool CdnProfiler::m_frameStarted = false;
	CdnProfTimer* CdnProfiler::m_pFrameTimer = 0;
	CdnProfilerFn* CdnProfiler::m_pCurrentFn = 0;
	float CdnProfiler::m_totalFrameTime = 0.00001f;
	
	//-----------------------------------------------------
	/**
	* Ctor
	*/
	CdnProfiler::CdnProfiler()  		
	{
	
	}

	//-----------------------------------------------------
	/**
	* Dtor
	*/
	CdnProfiler::~CdnProfiler()
	{		
	}

	//-----------------------------------------------------
	/**
	* Initializes profiler
	*/
	void CdnProfiler::Init()
	{
		m_pFrameTimer = new CdnProfTimer();		
		m_initialized = true;
		m_pCurrentFn = new CdnProfilerFn("global");
	}

	//-----------------------------------------------------
	/**
	* Releases memory
	*/
	void CdnProfiler::Shutdown()
	{
		if (m_pFrameTimer)
		{
			delete m_pFrameTimer;
			m_pFrameTimer = 0;
		}

		if (m_pCurrentFn)
		{
			delete m_pCurrentFn;
			m_pCurrentFn = 0;
		}

		m_initialized = false;
	}

	//-----------------------------------------------------
	/**
	* Begins profiler frame
	*/
	void CdnProfiler::BeginFrame()
	{
		assert (m_initialized);
		assert (!m_frameStarted);

		m_frameStarted = true;

		m_totalFrameTime = 0.0f;
		m_pCurrentFn->Start();		
		
	}

	//-----------------------------------------------------
	/**
	* Ends profiler frame
	*/
	void CdnProfiler::EndFrame()
	{
		assert (m_initialized);
		assert (m_frameStarted);

		m_frameStarted = false;

		m_pCurrentFn->Stop();

		fprintf(stdout, "Statistics:\n");
		fprintf(stdout, "Total Time: %f\n", m_totalFrameTime);
		PrintFnStats (m_pCurrentFn);
	}

	//-----------------------------------------------------
	/**
	* Starts profiling a function
	*/
	void CdnProfiler::BeginFn(const char* name)
	{
		assert (m_initialized);
		assert (m_frameStarted);

		if (m_pCurrentFn)
		{
			m_pCurrentFn = m_pCurrentFn->StartChildFunction(name);
		}
		else
		{
			m_pCurrentFn = new CdnProfilerFn(name);
			m_pCurrentFn->Start();
			
		}
	}

	//-----------------------------------------------------
	/**
	* Stops profiling a function
	*/
	void CdnProfiler::EndFn()
	{
		assert (m_initialized);
		assert (m_frameStarted);
		
		m_pCurrentFn->Stop();

		float totalTime = m_pCurrentFn->GetTotalTimeNoChildren();

		m_totalFrameTime += totalTime;

		CdnProfilerFn* parent = m_pCurrentFn->GetParent();
		if (parent)
		{
			m_pCurrentFn = parent;
		}

		
	}

	//-----------------------------------------------------
	/**
	* Prints statistics for a function recursively
	*/
	void CdnProfiler::PrintFnStats(CdnProfilerFn* fn)
	{
		const char* name = fn->GetName();
		float myProcTime = fn->GetTotalTimeNoChildren();
		float totalProcTime = fn->GetTotalTime();
		float framePercentage = 100.0f * myProcTime / m_totalFrameTime;
		float parentPercentage = 100.0f;
		const char* parentName = "";
		static int tabs = 0;
		
		CdnProfilerFn* parent = fn->GetParent();
		if (parent)
		{
			parentName = parent->GetName();
			parentPercentage = 100.0f * totalProcTime / parent->GetTotalTime();			
		}
		else
			tabs = 0;

		for (int i=0; i<tabs; i++)
		{
			fprintf(stdout, "___");
		}

		/*
		fprintf(stdout, 
			"%s::%s, Parent: %f - Total: %f [time:%f]\n",
			parentName, name, parentPercentage, framePercentage, myProcTime);
	
		*/
		fprintf(stdout, 
			"%s::%s - %f\n",
			parentName, name, parentPercentage);
		CdnProfilerFn::ChildrenList::const_iterator it = fn->GetChildren().begin();
		for (; it != fn->GetChildren().end(); ++it)
		{
			tabs++;
			PrintFnStats(it->second);
			tabs--;
		}
	}

}